package utils

import (
	"fmt"
	"github.com/golang-jwt/jwt/v5"
	"log"
	"net/http"
	"strings"
	"time"
)

type CustomClaims struct {
	UserId   int64
	Username string
	jwt.RegisteredClaims
}

type Token struct {
}

// ExpirationTime 过期时间
var ExpirationTime int = 60 * 60 * 60

// Secret 密钥
// var Secret = config.ViperConfig.Get("config.token.secret")
var Secret = "xxxxxxxxxx"

func (Token) GenerateToken(userId int64, username string) (token string, err error) {

	//unix := time.Now().Unix() + ExpirationTime
	mapClaims := CustomClaims{
		userId,
		username,
		jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
		},
	}
	token, err = jwt.NewWithClaims(jwt.SigningMethodHS256, mapClaims).SignedString([]byte(Secret))
	if err != nil {
		log.Println("token生成错误：" + err.Error())
		return "", err
	}
	return token, nil
}

func (Token) GetUserIdAndUserName(userToken string) (userId *int64, username *string, err error) {
	claims, err := Token{}.GetCustomClaims(userToken)
	if err != nil {
		return nil, nil, err
	}
	return &claims.UserId, &claims.Username, nil

}

func (Token) GetUserTokenAndUserIdAndUsername(w http.ResponseWriter, r *http.Request) (userToken *string,
	userId *int64, username *string, err error) {
	token := Token{}.GetUserToken(w, r)
	id, username, err := Token{}.GetUserIdAndUserName(token)
	if err != nil {
		return nil, nil, nil, err
	}
	return &token, id, username, nil
}

func (Token) GetUserToken(w http.ResponseWriter, r *http.Request) string {
	authorization := r.Header.Get("Authorization")
	if authorization == "" {
		return ""
	}
	token := strings.TrimSpace(strings.ReplaceAll(authorization, "Bearer", ""))
	return token
}

func (Token) VerifyToken(w http.ResponseWriter, r *http.Request) bool {
	token := Token{}.GetUserToken(w, r)
	claims, err := Token{}.GetCustomClaims(token)
	if err != nil {
		return false
	}
	e, err := claims.GetExpirationTime()
	nowTime := time.Now().Unix()
	tokenTime := e.Unix()
	if nowTime > tokenTime {
		log.Println("token已过期")
		return false
	}
	log.Println(fmt.Sprintf("剩余token有效时间：%v", e.Time.Sub(time.Now())))
	return true
}

func (Token) SetTokenExpiration(w http.ResponseWriter, r *http.Request) bool {
	token := Token{}.GetUserToken(w, r)
	claims, err := Token{}.GetCustomClaims(token)
	if err != nil {
		return false
	}
	claims.ExpiresAt.Sub(time.Now())
	expirationTime, err := claims.GetExpirationTime()
	if expirationTime.Time.Unix() < time.Now().Unix() {
		log.Println("token已过期")
		return false
	}
	return true
}

func (Token) GetCustomClaims(userToken string) (*CustomClaims, error) {
	token, err := jwt.ParseWithClaims(userToken, &CustomClaims{}, func(userToken *jwt.Token) (interface{}, error) {
		return []byte(Secret), nil
	})
	if err != nil {
		log.Println("token解析错误:" + err.Error())
		return nil, err
	}
	// 校验token
	//if token.Valid {
	//	return nil, errors.New("claim invalid")
	//}
	claims := token.Claims.(*CustomClaims)
	return claims, nil
}
